package com.tj.jinzao.widgets;


import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;

import com.tj.jinzao.common.Constant;

import java.util.List;

/**
 * 健康报告曲线图
 * Created by wjy on 2019/1/22.
 */
public class ChartView extends View implements GestureDetector.OnGestureListener {

    public final int Y_START_X = 30;//Y轴起点x
    public final int Y_START_Y = 130;//Y轴起点y
    public final int COLUMN_NUMBER = 6;//列数
    public final int ROW_NUMBER = 10;//行数
    protected Paint mRowLinePaint;//刻度线
    protected Paint mXYTextPaint;//刻度单位
    protected Paint mDataLinePaint;//折线图
    protected Path mAreaPath, mLinePath;//折线path


    protected float mY_startX, mY_startY; //Y轴起点x,y
    protected float mX_startX, mX_startY; //X轴起点x,y
    protected float mMoveX; //X轴移动量
    protected float mY_Range, mX_Range; //X,Y轴间距
    protected float mScaleY;//Y轴刻度缩放比率
    protected int mMinValueY;//Y轴起始value
    protected String[] mLabelY;    //Y的刻度文字
    protected String[] mLabelX;    //X的刻度

    protected float[] mData;      //数据
    private List<Integer> mDataInfoList;

    protected int mMoveIndex;//偏移日期
    protected int mSelectedIndex = -1;//选中日期

    protected Bitmap mWeightPoint, mWeightValueBg;
    protected Scroller mScroller = null;//滑动计算器
    private GestureDetector mDetector;//手势监听

    protected boolean mShowText = true;//是否显示单位

    public ChartView(Context context) {
        super(context);
        init();
    }

    public ChartView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    protected void init() {
        mScroller = new Scroller(getContext());
        mDetector = new GestureDetector(getContext(), this);
        Resources resources = getResources();
        mRowLinePaint = new Paint();
        mRowLinePaint.setColor(Color.parseColor("#FFB9BDD2"));
        mRowLinePaint.setStyle(Paint.Style.STROKE);
        mXYTextPaint = new Paint();
        mXYTextPaint.setColor(mRowLinePaint.getColor());
        mXYTextPaint.setTextSize(10 * Constant.SCALE_X);
        mDataLinePaint = new Paint();
        mDataLinePaint.setColor(Color.parseColor("#FFF5A623"));
        mDataLinePaint.setAntiAlias(true);
        mDataLinePaint.setStyle(Paint.Style.STROKE);
        mDataLinePaint.setStrokeWidth(8 * Constant.SCALE_Y);
        mAreaPath = new Path();
        mLinePath = new Path();
        mY_startX = Y_START_X * Constant.SCALE_X;
        mY_startY = Y_START_Y * Constant.SCALE_Y;
        mX_startX = mY_startX;

        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int height = getMeasuredWidth() * 100 / 325;
        setMeasuredDimension(Constant.SCREEN_WIDTH, height);
    }

    /**
     * 设置数据
     * @param data
     */
    public void setData(List<Integer> data) {
        mDataInfoList = data;
        if (data != null && data.size() != 0) {
        } else {
            mLabelY = new String[]{"40", "50", "60", "70", "80"};
            mMinValueY = 40;
            mSelectedIndex = -1;
            mMoveIndex = 0;
            mMoveX = 0;
            mData = null;
//            mScaleY = ((ROW_NUMBER - 1) * 10) / getChartHeight();//刻度与实际数值的缩放比率
        }
        mX_Range = (getChartWidth() - 60 * Constant.SCALE_X) / COLUMN_NUMBER * 2;
//        mY_Range = getChartHeight() / (ROW_NUMBER - 1);
        mMoveIndex = 0;
        invalidate();
    }

    //折线图显示宽度
    protected float getChartWidth() {
        return Constant.SCREEN_WIDTH;
    }

    /**
     * 根据value数值动态设置y轴参数
     */

    private PaintFlagsDrawFilter mPaintFlagsDrawFilter =
            new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);

    @Override
    protected void onDraw(Canvas c) {
//        Log.i("wjy","onDraw start time:"+ System.currentTimeMillis());
        c.setDrawFilter(mPaintFlagsDrawFilter);

        if (mLabelY != null) {
            for (int i = 0; i < ROW_NUMBER; i++) {
                mLinePath.reset();
                mLinePath.moveTo(mX_startX, mX_startY - mY_Range * i);
                mLinePath.lineTo(getWidth() - mX_startX, mX_startY - mY_Range * i);
                //刻度线
                c.drawPath(mLinePath, mRowLinePaint);  //刻度
                //y轴刻度单位
                c.drawText(mLabelY[i], mX_startX, mX_startY - mY_Range * i - 10 * Constant.SCALE_Y, mXYTextPaint);  //文字
            }
        }
//        Log.i("wjy","onDraw Y 轴:"+ (System.currentTimeMillis()));
        //设置X轴
        if (mData != null) {
            for (int i = -1; i < COLUMN_NUMBER + 1; i++) {
                float x = mX_startX + i * mX_Range / 2 - mMoveX;
                if (x >= mX_startX + mX_Range / (mData.length < 4 ? 5 : 2) && x < getWidth() - mX_startX - (mData.length < 4 ? mX_Range / 2 - 1 : 0)) {
                    mLinePath.reset();
                    mLinePath.moveTo(x, mX_startY - mY_Range * (ROW_NUMBER - 1));
                    mLinePath.lineTo(x, mX_startY);
                    //刻度线
                    c.drawPath(mLinePath, mRowLinePaint);  //刻度
                }
            }
        }
        if (mData == null) {
            return;
        }
        c.save();
        c.clipRect(mX_startX + mX_Range / 2 - 1 * Constant.SCALE_X, 0, getWidth() - mX_startX, getHeight());

        for (int i = -1; i < COLUMN_NUMBER / 2 + 1; i++) {
            int index = mData.length - 3 + i + mMoveIndex;//仅控制数据下标
            float x = mX_Range / 2 + mX_startX + i * mX_Range - mMoveX;
            if (index < mData.length && index > -1) {
                float startX = x - (mData.length < 3 ? mX_Range / mData.length : 0);
                float y = mX_startY - (mData[index] - mMinValueY) / mScaleY;
                //折线
                if (index + 1 < mData.length) {
                    float endY = mX_startY - (mData[index + 1] - mMinValueY) / mScaleY;
                    float endX = startX + mX_Range;
                    float centerX = startX + (endX - startX) / 2;
                    float centerY = y + (endY - y) / 2;
                    float quad1[] = getPoint(startX, y, centerX, centerY, 15, 0);
                    mAreaPath.reset();
                    mAreaPath.moveTo(startX, y);
                    mAreaPath.quadTo(quad1[0], quad1[1], centerX, centerY);
                    float quad2[] = getPoint(centerX, centerY, endX, endY, 15, -1);
                    mAreaPath.quadTo(quad2[0], quad2[1], endX, endY);
                    c.drawPath(mAreaPath, mDataLinePaint);
                }
            }
        }
        c.restore();
//        Log.i("wjy","onDraw 贝塞尔:"+ (System.currentTimeMillis()));
        for (int i = -1; i < COLUMN_NUMBER / 2 + 1; i++) {
            int index = mData.length - 3 + i + mMoveIndex;//仅控制数据下标
            float x = mX_Range / 2 + mX_startX + i * mX_Range - mMoveX;
            if (index < mData.length && index > -1) {
                float startX = x - (mData.length < 3 ? mX_Range / mData.length : 0);
                if (startX >= mX_startX + mX_Range / (mData.length < 4 ? 5 : 2) && startX < getWidth() - mX_startX) {
                    float y = mX_startY - (mData[index] - mMinValueY) / mScaleY;
                    //每个结点
//                    c.drawBitmap(mWeightPoint, startX - mWeightPoint.getWidth() / 2, y - mWeightPoint.getHeight() / 2, mWeightValuePaint);
                    //每个点value
                    //x轴刻度单位
                    if (mLabelX != null && index < mLabelX.length) {
                        c.drawText(mLabelX[index], startX, mX_startY + getHeight() / 10, mXYTextPaint);
                    }
                }
            }
        }
//        Log.i("wjy","onDraw 点:"+ (System.currentTimeMillis()));
        onUpdate();
    }

    //floats=test.getPoint(1f, 1f, 10f, 10f, 30, 0);   angle∈(0,90)  flag==0 up，flag!=0 down
    public static float[] getPoint(float xA, float yA, float xC, float yC, int angle, int flag) {
        float xD, yD;

        float xB = (xC + xA) / 2;
        float yB = (yC + yA) / 2;
        // the distance between two points
        float distanceAB = (float) Math.sqrt((xB - xA) * (xB - xA) + (yB - yA) * (yB - yA));

        float angleBAE = (float) Math.acos((xB - xA) / distanceAB);

        float angleBAD = ((float) (angle * Math.PI) / 180);

        float angleDAE = angleBAE - angleBAD;

        float distanceAD = (float) (distanceAB / (Math.cos(angleBAD)));

        if (yC < yA) {
            if (flag == 0) {
                xD = (float) (-distanceAD * Math.cos(angleDAE) + xC);
                yD = (float) (distanceAD * Math.sin(angleDAE) + yC);
            } else {
                xD = (float) (distanceAD * Math.cos(angleDAE) + xA);
                yD = (float) (-distanceAD * Math.sin(angleDAE) + yA);
            }
        } else {
            if (flag == 0) {
                xD = (float) (distanceAD * Math.cos(angleDAE) + xA);
                yD = (float) (distanceAD * Math.sin(angleDAE) + yA);
            } else {
                xD = (float) (-distanceAD * Math.cos(angleDAE) + xC);
                yD = (float) (-distanceAD * Math.sin(angleDAE) + yC);
            }
        }

        return new float[]{xD, yD};
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (mScroller != null && !mScroller.isFinished()) {
            mScroller.forceFinished(true);
        }
        return mDetector.onTouchEvent(event);
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return true;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        computeScroll1(distanceX, 0);
        return true;
    }

    protected void onUpdate() {
        if (mScroller != null && mScroller.computeScrollOffset()) {
            float scrollX;
            if (mLastFinalX == 0) {
                mLastFinalX = mScroller.getCurrX() - mScroller.getStartX();
                scrollX = mLastFinalX;
            } else {
                scrollX = mScroller.getCurrX() - mLastFinalX;
                mLastFinalX = mScroller.getCurrX();
            }
            computeScroll1(-scrollX / Constant.SCALE_X, 0);
        } else {
            if (mListener != null) mListener.scrollStop(mSelectedIndex);
        }
    }

    protected void computeScroll1(float distanceX, long delay) {
        if (mData == null || mData.length <= COLUMN_NUMBER / 2) {
            return;
        }
        if (distanceX > 0) {
            if (mMoveX + distanceX > 0 && mMoveIndex >= 0) {
                mMoveX = 0;
                if (mScroller != null) mScroller.forceFinished(true);
            } else {
                mMoveX += distanceX;
            }
        } else {
            if (mMoveX + distanceX < -mX_Range && mMoveIndex <= (-mData.length + COLUMN_NUMBER / 2)) {
                mMoveX = -mX_Range;
                if (mScroller != null) mScroller.forceFinished(true);
            } else {
                mMoveX += distanceX;
            }
        }
        boolean indexChanged = false;
        while (Math.abs(mMoveX) > mX_Range) {
            if (mMoveX > mX_Range) {
                mMoveX -= mX_Range;
                mMoveIndex++;
                indexChanged = true;
            } else if (mMoveX < -mX_Range) {
                mMoveX += mX_Range;
                mMoveIndex--;
                indexChanged = true;
            }
        }
        if (indexChanged && mScroller.isFinished()) {
            if (mListener != null) mListener.dataChanged(mSelectedIndex);
        }
        if (delay != 0) {
            postInvalidateDelayed(delay);
        } else {
            postInvalidate();
        }

    }

    @Override
    public void onLongPress(MotionEvent e) {
    }

    private float mLastFinalX;

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        if (mScroller != null) {
            mScroller.fling(0, 0, (int) velocityX, 0, -(int) mX_Range * 10, (int) mX_Range * 10, 0, 0);
//            mScroller.startScroll((int) velocityX / 2, 0, (int) velocityX, 10000);
            mLastFinalX = 0;
        }
        return true;
    }

    protected OnScrollListener mListener;

    public void setScrollListener(OnScrollListener scrollListener) {
        mListener = scrollListener;
    }

    public interface OnScrollListener {
        void scrollStop(int index);

        void dataChanged(int index);
    }

    public void recycleBitmap() {
        if (mWeightValueBg != null) mWeightValueBg.recycle();
        if (mWeightPoint != null) mWeightPoint.recycle();
    }


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
//        if (mWeightValueBg != null) mWeightValueBg.recycle();
//        if (mWeightPoint != null) mWeightPoint.recycle();
    }
}